let calcManager = {
    callStackDepth: 0,
    hierarchies: 0
}
class TreeNode {
    /**
    * @type string
    */
    value
    /**
    * @type string
    */
    label

    /**
    * @type TreeNode[]
    */
    children


    constructor(label, value) {
        this.value = value
        this.label = label
        this.children = []
    }
    /**
     * @param {TreeNode} newNode
     * @returns {TreeNode}
    */
    getChild(idDst, value) {
        let index = undefined
        for (let childIndex = 0; childIndex < this.children.length; childIndex++) {
            if (this.children[childIndex].label == idDst) {
                index = childIndex
            }
        }
        if (index === undefined) {
            let newNode = new TreeNode(idDst, value)
            this.children.push(newNode)
            return newNode
        } else {
            return this.children[index]
        }
    }

    toObject() {
        calcManager.callStackDepth += 1
        let propertyIDName =calcManager.hierarchies[calcManager.callStackDepth - 1].id.dst
        let propertyChildrenName =calcManager.hierarchies[calcManager.callStackDepth - 1].children.name
        let propertyValuesNames =calcManager.hierarchies[calcManager.callStackDepth - 1].values
        // let propertyValuesDstName =calcManager.hierarchies[callStackDepth - 1].values.dst
        let obj = {}
        if (this.children.length != 0) {
            let children = []
            for (let i = 0; i < this.children.length; i++) {
                children.push(this.children[i].toObject())
            }
            obj = {}
            obj[propertyIDName] = this.label;
            obj[propertyChildrenName] = children;
            for (let i = 0; i < propertyValuesNames.length; i++) {
                obj[propertyValuesNames[i].dst] = this.value[propertyValuesNames[i].dst]
            }
        } else {
            obj = {}
            obj[propertyIDName] = this.label;
            for (let i = 0; i < propertyValuesNames.length; i++) {
                obj[propertyValuesNames[i].dst] = this.value[propertyValuesNames[i].dst]
            }
        }
        calcManager.callStackDepth -= 1
        return obj
    }
}
/**
 * @param {Array} data: a list for 
 * @param {} hierarchies :a list for description in hierarchies
 */
const record2tree =  function (data, hierarchies) {
    calcManager.hierarchies = [{
        id: 'root',
        values: [],
        children: {
            'name': 'children',
        }
    }].concat(hierarchies);
    let root = new TreeNode("root", "");


    for (let i = 0; i < data.length; i += 1) {
        let record = data[i]
        let child = root
        for (let j = 1; j <calcManager.hierarchies.length; j++) {
            let valueNames =calcManager.hierarchies[j].values
            let values = {}
            for (let k in valueNames) {
                values[valueNames[k].dst] = record[valueNames[k].src] // 赋值
            }
            child = child.getChild(record[calcManager.hierarchies[j].id.dst], values)
        }
        // console.log("################################################")
    }
    // console.log(root.toObject())
    
    return root.toObject().children
}
 
exports.record2tree = record2tree